﻿/**
 *    Copyright 2012 Yohan Courbe
 *
 *  Licensed under the Apache License, Version 2.0 (the "License") 
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *      
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using SharpGL;
using SharpGL.SceneGraph.Assets;


namespace NetworkAnalyzer.Engines.Graphics.Radar
{
    public partial class GraphicsRadarForm : Form
    {
        private readonly Texture _worldTexture = new Texture();
        private CountryLookup.Country originCountry;
        private float _previousAngle;
        private PointF _point = new PointF(0, 0);
        /// <summary>
        /// 
        /// </summary>
        public GraphicsRadarForm()
        {
            GraphicsRadarSystem.Enabled = true;
            InitializeComponent();

            foreach (var coordinate in CountryLookup.Country.Countries.Where(coordinate => coordinate.CountryCode.Equals("BE")))
            {
                originCountry = coordinate;
                break;
            }

            ////  Get the OpenGL object, for quick access.
            OpenGL gl = openGLControl.OpenGL;

            ////  A bit of extra initialisation here, we have to enable textures.

            _worldTexture.Create(gl, @"Dependencies/world.gif");
        }

        private void openGLControl_OpenGLDraw(object sender, PaintEventArgs e)
        {
            OpenGL gl = openGLControl.OpenGL;

            gl.LoadIdentity();

            if (!_hideMap)
            {
                // scale map

                var mapWidth = (float)(Bounds.Width * 0.85f * _zoom / 4f);
                var mapHeight = (float)(Bounds.Height * 0.95f * _zoom / 4f);

                // center map

                var mapX = (float)((Bounds.Width - mapWidth) / 2) + _point.X;
                var mapY = (float)((Bounds.Height - mapHeight) / 2) + _point.Y;

                gl.DrawTexture(_worldTexture, mapX, mapY, mapWidth, mapHeight, 0, 0.5f, 0, 0.05f);
            }

            // Erase previous lines with transparent rectangle

            gl.Color(0, 0, 0, 0.06);
            gl.Begin(OpenGL.GL_QUADS);
            gl.Vertex(0, 0);
            gl.Vertex(Bounds.Width, 0);
            gl.Vertex(Bounds.Width, Bounds.Height);
            gl.Vertex(0, Bounds.Height);
            gl.End();

            lock (GraphicsRadarSystem.Locker)
            {
                foreach (var radarCountry in GraphicsRadarSystem.RadarCountries.Where(r => r.Activity > 100 && (r.Angle > _previousAngle-45 && r.Angle < _radarBuilder.Angle)))
                {
                    //Console.WriteLine("{0} {1}", radarCountry.Country.CountryCode, radarCountry.Angle);

                    var x = (int)(_screenCenterPoint.X + (radarCountry.Country.Longitude * _zoom) + _point.X);
                    var y = (int)(_screenCenterPoint.Y - (radarCountry.Country.Latitude * _zoom) +_point.Y);

                    gl.Color(0f, radarCountry.PointColor, 0f);
                    gl.FillCircle(x, y, 10);

                    gl.DrawText(x, Bounds.Height - y,               // Position. Fucking work around. Only god knows why I have to flip the y coordinate.
                                0.0f, 0.3f, 0.0f,                   // RGB Color (dark green)
                                "Consolas",                         // Font
                                14f,                                // Font-size
                                radarCountry.Country.CountryName);  // Text

                    radarCountry.Shown = true;
                }

                _previousAngle = _radarBuilder.Angle;
            }

            if (!_hideRadarEffect)
            {
                // Draw lines

                gl.LineWidth(2);
                gl.Color(0f, 0.5f, 0f, 1f);

                gl.Begin(OpenGL.GL_LINES);

                for (int i = 0; i < 20; i++)
                {
                    var p = _radarBuilder.NextLinePoint();

                    gl.Vertex(_radarBuilder.RadarCenterPoint.X, _radarBuilder.RadarCenterPoint.Y);
                    gl.Vertex(p.X, p.Y);
                }

                gl.End();

                // Draw circles and lines

                gl.LineWidth(2);
                gl.Color(0f, 0.3f, 0f, 1f);

                for (int i = 10; i < _screenCenterPoint.X * 2; i *= 2)
                {
                    gl.DrawCircle(_screenCenterPoint, i);
                }

                gl.Begin(OpenGL.GL_LINES);
                gl.Vertex(0, _screenCenterPoint.Y); gl.Vertex(_screenCenterPoint.X * 2, _screenCenterPoint.Y);
                gl.Vertex(_screenCenterPoint.X, 0); gl.Vertex(_screenCenterPoint.X, _screenCenterPoint.Y * 2);
                gl.End();
            }

            
        }

        private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
        {
            OpenGL gl = openGLControl.OpenGL;

            // Smooth
            gl.ShadeModel(OpenGL.GL_SMOOTH);

            // Enable transparency
            gl.Enable(OpenGL.GL_BLEND);
            gl.BlendFunc(OpenGL.GL_SRC_ALPHA, OpenGL.GL_ONE_MINUS_SRC_ALPHA);

            // Enable line width and smooth lines
            gl.Enable(OpenGL.GL_LINE_WIDTH);
            gl.Hint(OpenGL.GL_LINE_SMOOTH_HINT, OpenGL.GL_NICEST);
        }

        private void openGLControl_Resized(object sender, EventArgs e)
        {
            OpenGL gl = openGLControl.OpenGL;

            gl.MatrixMode(OpenGL.GL_PROJECTION);
            gl.LoadIdentity();
            gl.Ortho(0, Bounds.Width, Bounds.Height, 0, 0, 1);
            gl.MatrixMode(OpenGL.GL_MODELVIEW);

            _screenCenterPoint.X = (float)Bounds.Width / 2;
            _screenCenterPoint.Y = (float)Bounds.Height / 2;

            var radarWidth = (float)Math.Sqrt(Math.Pow(_screenCenterPoint.X, 2) + Math.Pow(_screenCenterPoint.Y, 2));

            _radarBuilder = new RadarBuilder(_screenCenterPoint, radarWidth, 0.1f);
        }

        private void openGLControl_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (_formFullScreen)
            {
                this.FormBorderStyle = FormBorderStyle.Sizable;
                this.TopMost = false;

                _formFullScreen = false;
            }
            else
            {
                this.FormBorderStyle = FormBorderStyle.None;
                this.TopMost = true;

                _formFullScreen = true;
            }
        }

        private bool _formFullScreen = false;
        private RadarBuilder _radarBuilder;
        private static PointF _screenCenterPoint;
        private static bool _hideRadarEffect;
        private static bool _hideMap;
        private double _zoom;

        private void openGLControl_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == 'r')
            {
                _hideRadarEffect = !_hideRadarEffect;
            }

            if (e.KeyChar == 'm')
            {
                _hideMap = !_hideMap;
            }

            if (e.KeyChar == 'z')
            {
                _point.Y-=3;
            }

            if (e.KeyChar == 's')
            {
                _point.Y+=3;
            }

            if (e.KeyChar == 'q')
            {
                _point.X-=3;
            }

            if (e.KeyChar == 'd')
            {
                _point.X+=3;
            }

            if (e.KeyChar == '+')
            {
                _zoom += 0.5;
            }

            if (e.KeyChar == '-')
            {
                _zoom -= 0.5;
            }
        }

        private void GraphicsRadarForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            GraphicsEngine.GraphicsEnginesManager.StopAll();
        }
    }
}
